package com.nifostasky.distributed.redisson;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RAtomicLong;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * redisson test
 *
 * @author ludangxin
 * @date 2021/8/15
 */
@Slf4j
@RestController
@RequestMapping("test")
@RequiredArgsConstructor
public class RedissonLockTestController {
    private final RedissonClient redissonClient;

    private static final String KEY = "book";
    /**
     * 没获取到锁的线程阻塞等待获取锁
     */
    @GetMapping("/lock")
    public void lock() {
        log.info("进入了测试方法～");
        RLock lock = null;
        try {
            lock = redissonClient.getLock("lock");
            lock.lock();
            log.info("获取到锁~");
            Thread.sleep(2000);
        }
        catch(InterruptedException e) {
            e.printStackTrace();
        }
        finally {
            //如果当前线程保持锁定则解锁
            if (null != lock && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    /**
     * 没获取到锁的线程直接返回锁状态
     */
    @GetMapping("tryLock")
    public void tryLock() {
        log.info("进入了测试方法～");
        RLock lock = null;
        try {
            lock = redissonClient.getLock("lock");
            if(lock.tryLock()) {
                log.info("获取到锁~");
                Thread.sleep(6000);
            }
            else {
                log.error("获取锁失败~");
            }
        }
        catch(InterruptedException e) {
            e.printStackTrace();
        }
        finally {
            //如果当前线程保持锁定则解锁
            if (null != lock && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    /**
     * 没获取到锁的线程尝试获取锁
     */
    @GetMapping("tryLockWithBlock")
    public void tryLockWithBlock() {
        log.info("进入了测试方法～");
        RLock lock = null;
        try {
            //非公平锁,随机取一个等待中的线程分配锁
            lock = redissonClient.getLock("lock");
            //公平锁,按照先后顺序依次分配锁
            //lock=redissonClient.getFairLock("lock");
            //最多等待锁3秒，5秒后强制解锁
            if(lock.tryLock(3, 5, TimeUnit.SECONDS)) {
                log.info("获取到锁~");
                Thread.sleep(1000);
            }
            else {
                log.error("获取锁失败~");
            }
        }
        catch(InterruptedException e) {
            e.printStackTrace();
        }
        finally {
            //如果当前线程保持锁定则解锁
            if (null != lock && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }



    /**
     * 购买图书
     */
    @GetMapping("buy1")
    public String buy1() {
        RLock lock = null;
        try {
            lock = redissonClient.getLock("lock");
            if(lock.tryLock(3, TimeUnit.SECONDS)) {
                RAtomicLong buyBefore = redissonClient.getAtomicLong(KEY);
                if(Objects.isNull(buyBefore)) {
                    log.error("未找到\"{}\"的库存信息~", KEY);
                    return "暂未上架～";
                }
                long buyBeforeL = buyBefore.get();
                if(buyBeforeL > 0) {
                    Long buyAfter = buyBefore.decrementAndGet();
                    log.info("剩余图书==={}", buyAfter);
                    return "购买成功～";
                }
                else {
                    log.info("库存不足～");
                    return "库存不足～";
                }
            }
            else {
                log.error("获取锁失败～");
            }
        }
        catch(Exception e) {
            e.printStackTrace();
        }
        finally {
            //如果当前线程保持锁定则解锁
            if(null != lock && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
        return "系统错误～";
    }
}